/*
 * Entity.cpp
 *
 *  Created on: 24.10.2012
 *      Author: Martin
 */

#ifdef _WIN32 
#include <windows.h> 
#endif

#include "Entity.h"

Entity::Entity(glm::vec3 _Pos, float _r, std::string _Name,
		std::string _modelFName, ModelPool *_mPool, PathFinder *_pathfinder)
{
	type = OBJ_ENTITY;
	parentType = OBJ_ENTITY;

	pathfinder = _pathfinder;
	Pos = _Pos;
	r = _r;
	Name = _Name;
	modelFName = _modelFName;
	mPool = _mPool;

	inserted = false;
	sleeping = false;
	underConstruction = true;

	markR = 0.0f;

	modelID.push_back(mPool->loadModel(modelFName, ""));
	markModelID = mPool->loadModel("mark", "");

	shaderID = Shader::sPool->getProgramID("model_default");


	markerShaderID = Shader::sPool->getProgramID("marker");
	shadowShaderID = 0;
	virtualShaderID = 0;

	Marked = false;

	animationPos = 1.0;
	unitBar = NULL;

	cost = 0;
	costGold = 0;

	// set default status to READY
	status = STATUS_READY;
	age = 100.0;
}

Entity::~Entity()
{
	delete (unitBar);
}

void Entity::control(float t)
{
}

DataTypes::Cube* Entity::getBBox()
{
	if (mPool->getModels()[modelID[0]]->isIsThereBBox())
		return mPool->getModels()[modelID[0]]->boundingBox;

	return NULL;
}

float Entity::getHightOfBBox()
{
	if (mPool->getModels()[modelID[0]]->isIsThereBBox())
	{
		return mPool->getModels()[modelID[0]]->boundingBox->getVertexes()[4].y
				+ Pos.y;
	}

	return 0.0;
}

void Entity::goTo(glm::vec2 pos)
{

}

glm::vec3 Entity::getPosition()
{
	return Pos;
}

glm::vec2 Entity::get2dPosition()
{
	glm::vec2 pos2d(Pos.x, Pos.z);
	return pos2d;
}

void Entity::draw(int shadertype)
{
	glUseProgram(shaderID);

	glUseProgram(0);
}

void Entity::drawMarker(float size) // draw marker
{
	if (Marked)
	{
		if (markR < 180.0)
			markR = markR + 1.0;
		else
			markR = 0.0;

		// get matrix
		glm::mat4 ModelMatrix = glm::scale(glm::mat4(1.0),
				glm::vec3(sin(markR * PI / 180.0) / 2.0 + 1.0));
		ModelMatrix = glm::scale(ModelMatrix, glm::vec3(size));
		glm::mat4 ViewMatrix = glm::translate(World::world->getView(), Pos);
		ViewMatrix = glm::rotate(ViewMatrix, markR, glm::vec3(0.0f, 1.0f, 0.0f));
		glm::mat4 MVP = World::world->getProjection() * ViewMatrix * ModelMatrix;

		// get light information
		glm::vec3 LightPos = World::world->getLightPos(); // position of light
		glm::vec3 LightDif = World::world->getLightDif(); // diffuse color of light
		glm::vec3 LightAmb = World::world->getLightAmb(); // ambient color of light
		glm::vec3 LightSpec = World::world->getLightSpe(); // specular color of light

		// start shader program
		// start shader program

		glUseProgram(markerShaderID);

		// send matrix to shader
		glUniformMatrix4fv(glGetUniformLocation(markerShaderID, "MVP"), 1, GL_FALSE,
				&MVP[0][0]);
		glUniformMatrix4fv(glGetUniformLocation(markerShaderID, "M"), 1, GL_FALSE,
				&ModelMatrix[0][0]);
		glUniformMatrix4fv(glGetUniformLocation(markerShaderID, "V"), 1, GL_FALSE,
				&ViewMatrix[0][0]);
		glUniform3f(
				glGetUniformLocation(markerShaderID, "LightPosition_worldspace"),
				LightPos.x, LightPos.y, LightPos.z);
		glUniform3f(glGetUniformLocation(markerShaderID, "lightAmb"), LightAmb.x,
				LightAmb.y, LightAmb.z);
		glUniform3f(glGetUniformLocation(markerShaderID, "lightDif"), LightDif.x,
				LightDif.y, LightDif.z);
		glUniform3f(glGetUniformLocation(markerShaderID, "lightSpec"), LightSpec.x,
				LightSpec.y, LightSpec.z);

		glUniform1i(glGetUniformLocation(markerShaderID, "tex0"), 0);

		glEnable(GL_BLEND);
		mPool->drawModelByID(markModelID);
		glDisable(GL_BLEND);
		glUseProgram(0);
	}
}

void Entity::drawBBox() // draw bounding box
{
	mPool->drawBBoxByModelID(modelID[0], Pos, r);
}

bool Entity::pointInEntity(glm::vec3 X)
{
	if (mPool->getModels()[modelID[0]]->isIsThereBBox())
	{
		// bounding box found
		return mPool->getModels()[modelID[0]]->boundingBox->pointInCube(r, Pos, X);
	}

	return 0;
}

// detection of collision with cube
bool Entity::CubeInEntity(DataTypes::Cube cube)
{
	if (mPool->getModels()[modelID[0]]->isIsThereBBox())
	{
		// bounding box found
		return mPool->getModels()[modelID[0]]->boundingBox->cubeInCubeThisMoved(
				cube, r, Pos);
	}

	return 0;
}

// create info bar for entity
void Entity::BuildUnitBar(std::string iconFName)
{
	// main form holding other info and butons
	unitBar = new Gadgets::Form(800, 64);
	unitBar->setPos(glm::vec2(0, 0));

	icon = new Gadgets::Form(64, 64);
	icon->setBackground(iconFName);
	icon->setPos(glm::vec2(5, 0));

	nameLabel = new Gadgets::Label(64, 16);
	nameLabel->setPos(glm::vec2(75, 8));
	nameLabel->setCaption(Name);

	unitBar->addItem(icon);
	unitBar->addItem(nameLabel);
}

const std::string& Entity::getModelFName() const
{
	return modelFName;
}

void Entity::setModelFName(const std::string& modelFName)
{
	this->modelFName = modelFName;
}

const std::string& Entity::getName() const
{
	return Name;
}

void Entity::setName(const std::string& name)
{
	Name = name;
}

const glm::vec3& Entity::getPos() const
{
	return Pos;
}

void Entity::setPos(const glm::vec3& pos)
{
	Pos = pos;
}

int Entity::getType() const
{
	return type;
}

void Entity::setType(int type)
{
	this->type = type;
}

float Entity::getAge() const
{
	return age;
}

void Entity::setAge(float age)
{
	this->age = age;

	if (age > 100.0)
		underConstruction = false;
}

bool Entity::isMarked() const
{
	return Marked;
}

void Entity::setMarked(bool marked)
{
	Marked = marked;
}

bool Entity::isInserted() const
{
	return inserted;
}

void Entity::setInserted(bool inserted)
{
	this->inserted = inserted;
}

float Entity::getR() const
{
	return r;
}

void Entity::setR(float r)
{
	this->r = r;
}

Gadgets::Form* Entity::getUnitBar()
{
	return unitBar;
}

void Entity::setUnitBar(Gadgets::Form* unitBar)
{
	this->unitBar = unitBar;
}

int Entity::getCost()
{
	return cost;
}

void Entity::setCost(int c)
{
	cost = c;
}

void Entity::setSleeping(bool sleeping)
{
	this->sleeping = sleeping;
}

int Entity::getCostGold()
{
	return costGold;
}

int Entity::getParentType()
{
	return parentType;
}

int Entity::getStatus()
{
	return status;
}

void Entity::setStatus(int status)
{
	this->status = status;
}

unsigned int Entity::resolveDecision(unsigned int id)
{
	return 0;
}

std::string Entity::getStringStatus()
{
	if (status == STATUS_SLEEPING)
		return "STATUS_SLEEPING";
	else if (status == STATUS_DEAD)
		return "STATUS_DEAD";
	else if (status == STATUS_VIRTUAL)
		return "STATUS_VIRTUAL";
	else if (status == STATUS_READY)
		return "STATUS_READY";
	else if (status == STATUS_UNDER_CONSTRUCTION)
		return "STATUS_UNDER_CONSTRUCTION";
	else if (status == STATUS_PLACED)
		return "STATUS_PLACED";
	else if (status == STATUS_CUT)
		return "STATUS_CUT";
	else if (status == STATUS_GOWORK)
		return "STATUS_GOWORK";
	else if (status == STATUS_GOHOME)
		return "STATUS_GOHOME";
	else if (status == STATUS_FLEEING)
		return "STATUS_FLEEING";
	else if (status == STATUS_WORKING)
		return "STATUS_WORKING";
	else if (status == STATUS_NEWJOB)
		return "STATUS_NEWJOB";
	else if (status == STATUS_DONE)
		return "STATUS_DONE";
	else if (status == STATUS_BACKHOME)
		return "STATUS_BACKHOME";
	return "";
}
